
#pragma __DATA_INCLUDES__

#ifndef DATAACCESS_HPP
#define	DATAACCESS_HPP

#include "collections/LinkedList.cpp"
#include "entities.hpp"
#include <iostream>
#include <fstream>


using std::string;
using namespace lms::entities;



namespace lms {
    namespace dataaccess {

        template< class TEntity>
        class GenericRepository {
        private:
            LinkedList<TEntity> *entities;
            string fileName;

            void GenericRepository<TEntity>::saveChanges() {

                std::fstream out(fileName.c_str(), std::ios::out | std::ios::binary);

                
                Node< TEntity >* temp = entities->getFirst();
                while (temp != null) {

                    typename TEntity::serializable serial = *(temp->getData());
                    out.write(reinterpret_cast<char*> (&serial), sizeof ( typename TEntity::serializable));

                    temp = temp->getNext();
                }

                out.close();
            }
  
            bool isFileExist()
            {
                FILE* pf;
                if( (pf = fopen( fileName.c_str(),"rb" ) ) == NULL )
                    return false;
                return true;
            } 
            
            std::streampos getFileSize( std::fstream& in )
            {
                std::streampos fileBytesSizes;
                in.seekg( 0,std::ios::end );
                fileBytesSizes = in.tellg() / sizeof( typename TEntity::serializable );
                
                in.seekg( 0,std::ios::beg );  
                return fileBytesSizes;
            }
            
            void GenericRepository<TEntity>::loadData() {
                if (entities == null)
                    return;
                
                if( !isFileExist() )
                    return;

                std::fstream in(fileName.c_str(), std::ios::in | std::ios::binary);

                std::streampos fileBytesSizes = getFileSize( in );
                
                for( int i=0;i< fileBytesSizes;++i ){
                    
                    typename TEntity::serializable serial;
                    in.read(reinterpret_cast<char*> (&serial), sizeof ( typename TEntity::serializable));

                    
                    TEntity* restoredObject = new TEntity();
                    restoredObject->parseSerializable(serial);

                    entities->add(restoredObject);
                }
                in.close();
            }


        public:

            GenericRepository(string fileName) {
                this->entities = new LinkedList<TEntity > ();
                this->fileName = fileName;
                loadData();
            }

            LinkedList<TEntity>* get() {
                return entities;
            }

            void add(TEntity *entity) { 
                  entities->add(entity);
                saveChanges();
            }

            void edit(TEntity *entity, int index) {
                entities->edit(entity, index);
                saveChanges();
            } 

            int getLength()
            {
                return entities->getLength();
            }
            void remove(int index) {              
                entities->remove(index);
                saveChanges();
            }
            string getFileName()
            {
                return fileName;
            }

        };


    }
}

#endif	/* DATAACCESS_HPP */

